package com.nf.mvc.util;

import static com.nf.mvc.util.ClassUtils.isAssignable;

public interface ExceptionUtils {
    /**
     * 此方法只要参数不是一个null的就不会返回一个null的异常
     * 其基本逻辑就是在异常链上找cause，直到null或不等于参数指定的异常为止，也就是找出最原始的异常
     * <p>
     * 反射调用会把任何方法调用抛出的异常用InvocationTargetException异常包装起来，想得到真正的异常需要调用getCause方法获取
     * </p>
     * <p>下面的代码学生可能更容易理解，但没有考虑递归cause的问题，所以为了阻止这种无限循环的问题，必须加上root!=cause
     * <pre class="code">
     *     private static Throwable findRoot(Throwable e) {
     *       Throwable root = e;
     *       while (root != null) {
     *          if (root.getCause() == null) {
     *              break;
     *          }
     *          root = root.getCause();
     *       }
     *       return root;
     *     }
     * </pre>
     * </p>
     * <p>
     * 参考: <br/>
     * <a href="https://stackoverflow.com/questions/6020719/what-could-cause-java-lang-reflect-invocationtargetexception">InvocationTargetException</a><br/>
     * <a href="https://stackoverflow.com/questions/17747175/how-can-i-loop-through-exception-getcause-to-find-root-cause-with-detail-messa">root exception</a>
     * <a href="https://www.baeldung.com/java-exception-root-cause">Find an Exception’s Root Cause</a>
     * </p>
     *
     * @param ex 当前抛出的异常
     * @return 返回最源头的异常
     */
    static Throwable getRootCause(Throwable ex) {
        Throwable cause;
        Throwable root = ex;
        while (null != (cause = root.getCause()) && (root != cause)) {
            root = cause;
        }
        return root;
    }

    static int compare(Class<? extends Throwable> ex1Class, Class<? extends Throwable> ex2Class) {
        return ex1Class == ex2Class ? 0 : isAssignable(ex1Class, ex2Class) ? 1 : -1;
    }
}
